/**
 ******************************************************************************
 * @file    bsp_ds18b20.c
 * @author  fire
 * @version V1.0
 * @date    2015-xx-xx
 * @brief   DS18B20温度传感器应用函数接口
 ******************************************************************************
 * @attention
 *
 * 实验平台:野火  STM32 MINI 开发板
 * 论坛    :http://www.firebbs.cn
 * 淘宝    :https://fire-stm32.taobao.com
 *
 ******************************************************************************
 */

#include "bsp_ds18b20.h"
#include "../../Core/Inc/gpio.h"
#include "../my_define.h"
/* 可以在下面的宏定义中把后面的延时函数替换换SysTick的延时函数，就是想用那个就换成那个的 */

/************************** DS18B20 函数宏定义********************************/

static void    DS18B20_GPIO_Config(void);
static void    DS18B20_Mode_IPU(void);
static void    DS18B20_Mode_Out_PP(void);
static void    DS18B20_Rst(void);
static uint8_t DS18B20_Presence(void);
static uint8_t DS18B20_ReadBit(void);
static uint8_t DS18B20_ReadByte(void);
static void    DS18B20_WriteByte(uint8_t dat);
static void    DS18B20_SkipRom(void);
static void    DS18B20_MatchRom(void);
static void    DS18B20_DQ_0(void);
static void    DS18B20_DQ_1(void);
static uint8_t DS18B20_DQ_READ(void);
static void    DS18B20_DELAY_US(uint32_t us);
/*
 * 函数名：DS18B20_GPIO_Config
 * 描述  ：配置DS18B20用到的I/O口
 * 输入  ：无
 * 输出  ：无
 */
 void DS18B20_GPIO_Config(void)
{
//    GPIO_InitTypeDef gpio = {0};
//    gpio.Pin = GPIO_PIN_6;
//    gpio.Mode = GPIO_MODE_OUTPUT_OD;
//    gpio.Pull = GPIO_PULLUP;
//    gpio.Speed = GPIO_SPEED_FREQ_HIGH;
//    HAL_GPIO_Init(GPIOA, &gpio);
//    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);  // 释放总线
}
void DS18B20_gpio_test()
{
	//DS18B20_DELAY_START();
	DS18B20_DQ_0();
	DS18B20_DELAY_US(1000);
	//DS18B20_DELAY_START();
	DS18B20_DQ_1();
	DS18B20_DELAY_US(1000);
}
static void DS18B20_DQ_0(void)
{
//    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
//    GPIO_InitStruct.Pin              = GPIO_PIN_6;
//    GPIO_InitStruct.Mode             = GPIO_MODE_OUTPUT_PP;
//    GPIO_InitStruct.Pull             = GPIO_NOPULL;
//    GPIO_InitStruct.Speed            = GPIO_SPEED_FREQ_HIGH;
//    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
};
static void DS18B20_DQ_1(void)
{
//    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
//    GPIO_InitStruct.Pin              = GPIO_PIN_6;
//    GPIO_InitStruct.Mode             = GPIO_MODE_OUTPUT_PP;
//    GPIO_InitStruct.Pull             = GPIO_NOPULL;
//    GPIO_InitStruct.Speed            = GPIO_SPEED_FREQ_LOW;
//    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
};
uint8_t DS18B20_DQ_READ()
{
    // uint8_t level = 0;
    // level         = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6);
//     int     CNT   = 0;
//    uint8_t level = 0;
//    do
//    {
//        level = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6);
//        CNT++;
//        DS18B20_DELAY_US(1);
//    } while (level == 1 && CNT < 5);
//    return level;   
    
    return HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6);
}
static void DS18B20_Mode_IPU(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
    GPIO_InitStruct.Pin              = GPIO_PIN_6;
    GPIO_InitStruct.Mode             = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull             = GPIO_NOPULL;
	GPIO_InitStruct.Speed            = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
static void DS18B20_Mode_Out_PP(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = { 0 };
    GPIO_InitStruct.Pin              = GPIO_PIN_6;
    GPIO_InitStruct.Mode             = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull             = GPIO_PULLUP;
    GPIO_InitStruct.Speed            = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
}
/**
  * @brief  微秒级阻塞延迟函数
  * @param  us : 需要延迟的微秒数（范围：1 ~ 4294967295us）
  * @note   使用32位计数器自动处理溢出回绕
  */
void DS18B20_DELAY_US(uint32_t us)
{
//   volatile uint32_t start = machine.tick_1us;  // 获取起始时间戳
//    volatile uint32_t end;

//    // 处理时间戳溢出回绕（自动利用无符号整型溢出特性）
//    if((UINT32_MAX - start) >= us) {
//        end = start + us;  // 无溢出情况
//    } else {
//        end = us - (UINT32_MAX - start) - 1;  // 溢出后重新计算终点
//    }

//    // 等待时间到达（处理计数器溢出）
//    while(machine.tick_1us - start < us) {
//        // 当发生溢出时自动修正判断条件
//        if(machine.tick_1us < start) {
//            break;  // 此时已满足 machine.tick_1us - start > us（因溢出）
//        }
//    }
		volatile static uint32_t i , j;
		for(i=0; i<us; i++)
	{
		 for(j=0; j< 1; j++)
		{
		}
	}
}
volatile uint32_t start_tick = 0;
void DS18B20_DELAY_START()
{
	start_tick = machine.tick_1us;  // 获取起始时间戳
}
void DS18B20_DELAY_ABSOLUTE_US(uint32_t us)
{
    volatile uint32_t end;
    // 处理时间戳溢出回绕（自动利用无符号整型溢出特性）
    if((UINT32_MAX - start_tick) >= us) {
        end = start_tick + us;  // 无溢出情况
    } else {
        end = us - (UINT32_MAX - start_tick) - 1;  // 溢出后重新计算终点
    }

    // 等待时间到达（处理计数器溢出）
    while(machine.tick_1us - start_tick < us) {
        // 当发生溢出时自动修正判断条件
        if(machine.tick_1us < start_tick) {
            break;  // 此时已满足 machine.tick_1us - start > us（因溢出）
        }
    }
}
/**
 * @brief  DS18B20 初始化函数
 * @param  无
 * @retval 无
 */
uint8_t DS18B20_Init(void)
{
    DS18B20_Mode_Out_PP();

    DS18B20_DQ_1();

    DS18B20_Rst();

    return DS18B20_Presence();
}

/*
 *主机给从机发送复位脉冲
 */
static void DS18B20_Rst(void)
{
    /* 主机设置为推挽输出 */
    DS18B20_Mode_Out_PP();

    DS18B20_DQ_0();
    /* 主机至少产生480us的低电平复位信号 */
    DS18B20_DELAY_US(750);

    /* 主机在产生复位信号后，需将总线拉高 */
    DS18B20_DQ_1();

    /*从机接收到主机的复位信号后，会在15~60us后给主机发一个存在脉冲*/
    DS18B20_DELAY_US(15);
}

/*
 * 检测从机给主机返回的存在脉冲
 * 0：成功
 * 1：失败
 */
static uint8_t DS18B20_Presence(void)
{
    uint8_t pulse_time = 0;

    /* 主机设置为上拉输入 */
    DS18B20_Mode_IPU();

    /* 等待存在脉冲的到来，存在脉冲为一个60~240us的低电平信号
     * 如果存在脉冲没有来则做超时处理，从机接收到主机的复位信号后，会在15~60us后给主机发一个存在脉冲
     */
    while (DS18B20_DQ_READ() && pulse_time < 100)
    {
        pulse_time++;
        DS18B20_DELAY_US(1);
    }
    /* 经过100us后，存在脉冲都还没有到来*/
    if (pulse_time >= 100)
        return 1;
    else
        pulse_time = 0;

    /* 存在脉冲到来，且存在的时间不能超过240us */
    while (!DS18B20_DQ_READ() && pulse_time < 240)
    {
        pulse_time++;
        DS18B20_DELAY_US(1);
    }
    if (pulse_time >= 240)
        return 1;
    else
        return 0;
}

/*
 * 从DS18B20读取一个bit
 */
static uint8_t DS18B20_ReadBit(void)
{
    uint8_t dat;

    /* 读0和读1的时间至少要大于60us */
    DS18B20_Mode_Out_PP();
    /* 读时间的起始：必须由主机产生 >1us <15us 的低电平信号 */
    DS18B20_DQ_0();
    DS18B20_DELAY_US(10);

    /* 设置成输入，释放总线，由外部上拉电阻将总线拉高 */
    DS18B20_Mode_IPU();
     DS18B20_DELAY_US(20);
		
    if (DS18B20_DQ_READ() == SET)
        dat = 1;
    else
        dat = 0;

    /* 这个延时参数请参考时序图 */
    DS18B20_DELAY_US(25);

    return dat;
}

/*
 * 从DS18B20读一个字节，低位先行
 */
static uint8_t DS18B20_ReadByte(void)
{
    uint8_t i, j, dat = 0;

    for (i = 0; i < 8; i++)
    {
        j   = DS18B20_ReadBit();
         dat = (dat) | (j << i);
    }

    return dat;
}

/*
 * 写一个字节到DS18B20，低位先行
 */
static void DS18B20_WriteByte(uint8_t dat)
{
    uint8_t i, testb;
    DS18B20_Mode_Out_PP();

    for (i = 0; i < 8; i++)
    {
        testb = dat & 0x01;
        dat   = dat >> 1;
        /* 写0和写1的时间至少要大于60us */
        if (testb)
        {
            DS18B20_DQ_0();
            /* 1us < 这个延时 < 15us */
            DS18B20_DELAY_US(8);

            DS18B20_DQ_1();
            DS18B20_DELAY_US(58);
        }
        else
        {
            DS18B20_DQ_0();
            /* 60us < Tx 0 < 120us */
            DS18B20_DELAY_US(70);

            DS18B20_DQ_1();
            /* 1us < Trec(恢复时间) < 无穷大*/
            DS18B20_DELAY_US(2);
        }
    }
}

/**
 * @brief  跳过匹配 DS18B20 ROM
 * @param  无
 * @retval 无
 */
static void DS18B20_SkipRom(void)
{
    DS18B20_Rst();

    DS18B20_Presence();

    DS18B20_WriteByte(0XCC); /* 跳过 ROM */
}

/**
 * @brief  执行匹配 DS18B20 ROM
 * @param  无
 * @retval 无
 */
static void DS18B20_MatchRom(void)
{
    DS18B20_Rst();

    DS18B20_Presence();

    DS18B20_WriteByte(0X55); /* 匹配 ROM */
}

/*
 * 存储的温度是16 位的带符号扩展的二进制补码形式
 * 当工作在12位分辨率时，其中5个符号位，7个整数位，4个小数位
 *
 *         |---------整数----------|-----小数 分辨率 1/(2^4)=0.0625----|
 * 低字节  | 2^3 | 2^2 | 2^1 | 2^0 | 2^(-1) | 2^(-2) | 2^(-3) | 2^(-4) |
 *
 *
 *         |-----符号位：0->正  1->负-------|-----------整数-----------|
 * 高字节  |  s  |  s  |  s  |  s  |    s   |   2^6  |   2^5  |   2^4  |
 *
 *
 * 温度 = 符号位 + 整数 + 小数*0.0625
 */
/**
 * @brief  在跳过匹配 ROM 情况下获取 DS18B20 温度值
 * @param  无
 * @retval 温度值
 */
float DS18B20_GetTemp_SkipRom(void)
{
    uint8_t tpmsb, tplsb;
    short   s_tem;
    float   f_tem;

    DS18B20_SkipRom();
    DS18B20_WriteByte(0X44); /* 开始转换 */

    DS18B20_SkipRom();
    DS18B20_WriteByte(0XBE); /* 读温度值 */

    tplsb = DS18B20_ReadByte();
    tpmsb = DS18B20_ReadByte();

    s_tem = tpmsb << 8;
    s_tem = s_tem | tplsb;

    if (s_tem < 0) /* 负温度 */
        f_tem = (~s_tem + 1) * 0.0625;
    else
        f_tem = s_tem * 0.0625;

    return f_tem;
}

/**
 * @brief  在匹配 ROM 情况下获取 DS18B20 温度值
 * @param  ds18b20_id：用于存放 DS18B20 序列号的数组的首地址
 * @retval 无
 */
void DS18B20_ReadId(uint8_t* ds18b20_id)
{
    uint8_t uc;

    DS18B20_WriteByte(0x33);  // 读取序列号

    for (uc = 0; uc < 8; uc++)
        ds18b20_id[uc] = DS18B20_ReadByte();
}

/**
 * @brief  在匹配 ROM 情况下获取 DS18B20 温度值
 * @param  ds18b20_id：存放 DS18B20 序列号的数组的首地址
 * @retval 温度值
 */
float DS18B20_GetTemp_MatchRom(uint8_t* ds18b20_id)
{
    static uint8_t tpmsb, tplsb, i;
    static short   s_tem;
    static float   f_tem;

    DS18B20_MatchRom();  // 匹配ROM

    for (i = 0; i < 8; i++)
      {  DS18B20_WriteByte(ds18b20_id[i]);}
	
    DS18B20_WriteByte(0X44); /* 开始转换 */

    DS18B20_MatchRom();  // 匹配ROM

    for (i = 0; i < 8; i++)
      {  DS18B20_WriteByte(ds18b20_id[i]);}

    DS18B20_WriteByte(0XBE); /* 读温度值 */

    tplsb = DS18B20_ReadByte();
    tpmsb = DS18B20_ReadByte();

		machine.c1 = tplsb;
		machine.c2 = tpmsb;
			
    s_tem = tpmsb << 8;
    s_tem = s_tem | tplsb;

    if (s_tem < 0) /* 负温度 */
        f_tem = (~s_tem + 1) * 0.0625;
    else
        f_tem = s_tem * 0.0625;

    return f_tem;
}

/*************************************END OF FILE******************************/
